//
//  DWNetworkViewController.m
//  OCAPPDemo
//
//  Created by 杨冬武 on 2021/5/25.
//

#import "DWNetworkViewController.h"
#import <WebKit/WebKit.h>
#import "AppDelegate.h"

@interface DWNetworkViewController () <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>

/// 会话
@property (nonatomic, strong) NSURLSession *session;
@property (nonatomic, strong) NSURLSession *bgSession;

/// buffer 用于存储获取到的数据
@property (nonatomic, strong) NSMutableData *receiveData;

/// 下载任务
@property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;
/// 下载失败或者下载取消后的恢复数据
@property (nonatomic, strong) NSData *resumeData;

/// webView 用于加载请求到的数据
@property (weak, nonatomic) IBOutlet WKWebView *webView;
@property (weak, nonatomic) IBOutlet UILabel *progressLabel;
@property (weak, nonatomic) IBOutlet UIProgressView *progressView;
@property (weak, nonatomic) IBOutlet UILabel *persentLabel;

@end

@implementation DWNetworkViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    configuration.waitsForConnectivity = YES;
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
    self.session = session;
    
    NSURLSessionConfiguration *bgconfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"MySession"];
    [bgconfiguration setDiscretionary:YES];
    bgconfiguration.sessionSendsLaunchEvents = YES;
    NSURLSession *bgsession = [NSURLSession sessionWithConfiguration:bgconfiguration delegate:self delegateQueue:nil];
    self.bgSession = bgsession;
    
    self.receiveData = [[NSMutableData alloc] init];
    
    /*
     手动创建WKWebView
     CGRect f = CGRectMake(0, kScreenHeight / 2, kScreenWidth, kScreenHeight / 2);
     WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
     self.webview = [[WKWebView alloc] initWithFrame:f configuration:config];
     [self.view addSubview:self.webview];
     */
}

#pragma mark - data task

/// 使用completionHandler接受数据
/// @param sender sender description
- (IBAction)dataTask:(id)sender {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://httpbin.org/get"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
    //request.HTTPMethod = @"POST";
    //request
    NSURLSessionDataTask *dataTask =  [self.session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"%@",[NSThread currentThread]);
        if (error) {
            NSLog(@"error : %@", error);
        } else {
            NSLog(@"success : %@, response : %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding], response);
        }
    }];
    [dataTask resume];
}

/// 使用代理接受数据
/// @param sender sender
- (IBAction)dataTaskReceiveDelegate:(id)sender {
    NSURL *url = [NSURL URLWithString:@"https://www.example.com/"];
    NSURLSessionTask * task = [self.session dataTaskWithURL:url];
    [task resume];
}


#pragma mark - upload task

- (IBAction)uploadTask:(id)sender {
    
    NSData *jsonData = [self jsonString];
    
    NSLog(@"%@", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]);
    
    NSURL *url = [NSURL URLWithString:@"https://httpbin.org/post"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    
    NSURLSessionUploadTask * task = [self.session uploadTaskWithRequest:request fromData:jsonData completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        if (error) {
            NSLog(@"error = %@", error);
            return;
        }
        
        if (![response isKindOfClass:[NSHTTPURLResponse class]]) {
            return;
        }
        NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
        NSLog(@"response = %@", httpResponse);
        if (httpResponse.statusCode < 200 || httpResponse.statusCode >= 300) {
            return;
        }
        
        if (![response.MIMEType isEqualToString:@"application/json"]) {
            return;
        }
        
        if (!data) {
            return;
        }
        
        NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        
        NSLog(@"success = %@", dataString);
        
    }];
    
    [task resume];
    
}

- (NSData *)jsonString {
    NSDictionary *dic = @{@"customerId": @"12345", @"items": @[@"Cheese pizza", @"Diet soda"]};
    NSError *err;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&err];
    // NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:(NSUTF8StringEncoding)];
    return jsonData;
}

#pragma mark - downloadTask

- (IBAction)downloadTask:(id)sender {
    
    self.progressView.progress = 0;
    self.persentLabel.text = @"0%%";
    NSURL *url = [NSURL URLWithString:@"https://dldir1.qq.com/weixin/mac/WeChatMac.dmg"];
    NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:url];
    [task resume];
    self.downloadTask = task;
    
    /*
     NSURL *url = [NSURL URLWithString:@"https://dldir1.qq.com/weixin/mac/WeChatMac.dmg"];
    NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        if (error) {
            NSLog(@"error = %@", error);
            return;
        }

        if (!url) {
            return;
        }

        if (![response isKindOfClass:[NSHTTPURLResponse class]]) {
            return;
        }
        NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
        NSLog(@"response = %@", httpResponse);
        if (httpResponse.statusCode < 200 || httpResponse.statusCode >= 300) {
            return;
        }

        if (![response.MIMEType isEqualToString:@"application/json"]) {
            return;
        }

    }];
     
     [task resume];
     */
    
}

- (IBAction)backgroundDownloadTask:(id)sender {
    NSURL *url = [NSURL URLWithString:@"https://dldir1.qq.com/weixin/mac/WeChatMac.dmg"];
    NSURLSessionDownloadTask *task = [self.bgSession downloadTaskWithURL:url];
    task.earliestBeginDate = [NSDate date];
    [task setCountOfBytesClientExpectsToSend:500];
    [task setCountOfBytesClientExpectsToReceive:16 * 1024 * 1024];
    [task resume];
}

- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
    
    NSLog(@"%lld, %lld, %lld", bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
   
    CGFloat p = (CGFloat)totalBytesWritten / (CGFloat)totalBytesExpectedToWrite;
    CGFloat kb_s = (CGFloat)bytesWritten / 1024;
    CGFloat totalMB = (CGFloat)totalBytesExpectedToWrite / 1024 / 1024;
    CGFloat cmb = (CGFloat)totalBytesWritten / 1024 / 1024;
    
    dispatch_async(dispatch_get_main_queue(), ^{
        self.persentLabel.text = [NSString stringWithFormat:@"%d%%", (int)(p * 100)];
        [self.progressView setProgress:p animated:YES];
        self.progressLabel.text = [NSString stringWithFormat:@"%.2fmb/%.2fmb %.2fkb/s", cmb, totalMB, kb_s];
    });
    
}

- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location {
    NSLog(@"%s, %@", __FUNCTION__, location);
    
    if (!location) {
        return;
    }
    
    NSError *err;
    NSURL *documentUrl = [[NSFileManager defaultManager] URLForDirectory:(NSDocumentDirectory) inDomain:(NSUserDomainMask) appropriateForURL:nil create:false error:&err];
    if (err) {
        return;
    }
    
    // 创建一个指定的目录
    NSURL *saveUrl = [documentUrl URLByAppendingPathComponent:[location lastPathComponent]];
    
    // 将文件保存到指定的目录下
    [[NSFileManager defaultManager] moveItemAtURL:location toURL:saveUrl error:&err];
    
    if (err) {
        return;
    }
    
    NSLog(@"文件保存成功");
    
}

- (IBAction)cancelDownloadTask:(id)sender {
    [self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
        if (resumeData) {
            // 取消任务后保存resumeData 可以后续用于继续下载
            NSLog(@"cancelByProducingResumeData = %@", resumeData);
            self.resumeData = resumeData;
        }
    }];
}

- (IBAction)resumeDownloadTask:(id)sender {
    
    if (self.resumeData) {
        
        NSURLSessionDownloadTask *task = [self.session downloadTaskWithResumeData:self.resumeData];
        [task resume];
        self.downloadTask = task;
        
    }
    
}



#pragma mark - NSURLSessionDelegate

/* The last message a session receives.  A session will only become
 * invalid because of a systemic error or when it has been
 * explicitly invalidated, in which case the error parameter will be nil.
 */
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error {
    NSLog(@"%s", __FUNCTION__);
}

/* If implemented, when a connection level authentication challenge
 * has occurred, this delegate will be given the opportunity to
 * provide authentication credentials to the underlying
 * connection. Some types of authentication will apply to more than
 * one request on a given connection to a server (SSL Server Trust
 * challenges).  If this delegate message is not implemented, the
 * behavior will be to use the default handling, which may involve user
 * interaction.
 */
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
    NSLog(@"%s", __FUNCTION__);
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSURLCredential *credietial = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
        if (completionHandler) {
            completionHandler(NSURLSessionAuthChallengeUseCredential, credietial);
        }
    }
}

/* If an application has received an
 * -application:handleEventsForBackgroundURLSession:completionHandler:
 * message, the session delegate will receive this message to indicate
 * that all messages previously enqueued for this session have been
 * delivered.  At this time it is safe to invoke the previously stored
 * completion handler, or to begin any internal updates that will
 * result in invoking the completion handler.
 */
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
    NSLog(@"%s", __FUNCTION__);
    
    dispatch_async(dispatch_get_main_queue(), ^{
        AppDelegate *ad = [UIApplication sharedApplication].delegate;
        if (ad) {
            ad.backgroundCompletionHandler();
        }
    });
    
}



#pragma mark - NSURLSessionTaskDelegate

/// 任务完成回调
/// @param session 会话
/// @param task 任务
/// @param error 错误
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    NSLog(@"%s", __FUNCTION__);
    
    if (error) {
        NSData *resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
        if (resumeData) {
            // 下载失败时存储resumeData 后续可以使用此数据进行恢复
            NSLog(@"resumeData = %@", resumeData);
            self.resumeData = resumeData;
        }
        return;
    }
    
    // 正常
    NSString *str = [[NSString alloc] initWithData:self.receiveData encoding:NSUTF8StringEncoding];
    NSURL *url = task.currentRequest.URL;
    // 需要在主线程进行UI更新
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.webView loadHTMLString:str baseURL:url];
    });
    
}

#pragma mark - NSURLSessionDataDelegate

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
    NSLog(@"%s", __FUNCTION__);
    if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        if (httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 && [httpResponse.MIMEType isEqualToString:@"text/html"]) {
            completionHandler(NSURLSessionResponseAllow);
            return;
        }
    }
    completionHandler(NSURLSessionResponseCancel);
}


/// 接收到数据
/// @param session 会话
/// @param dataTask 任务
/// @param data 数据
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
    NSLog(@"%s", __FUNCTION__);
    // 将数据写入到buffer
    [self.receiveData appendData:data];
}

- (void)dealloc {
    [self.session invalidateAndCancel];
}

@end
